
#ifndef PUBLIC_KEY_HPP
#define PUBLIC_KEY_HPP

#include "wire/hash.hpp"
#include "wire/serialize.hpp"
#include "wire/uint256.hpp"

#include <stdexcept>
#include <vector>

struct KeyID: public uint160
{
    KeyID(): uint160(){}
    explicit KeyID(const uint160& in): uint160(in) {}
    bool operator<(KeyID const& another) const
    {
        return memcmp(data,another.data,sizeof(data)) < 0;
    }
    bool operator==(KeyID const& another) const
    {
        return memcmp(data,another.data,sizeof(data)) == 0;
    }
};

class PublicKey
{
public:
    /**
     * secp256k1:
     * 
     */
    static const unsigned int kPublicKeySize = 65;
    static const unsigned int kSignatureSize = 72;
private:
    unsigned char vch[kPublicKeySize];

public: 
    PublicKey(){ bzero(vch, kPublicKeySize); }

    template <typename T>
    void set(const T pbegin,const T pend)
    {
        int len = pbegin == pend ? 0 : kPublicKeySize;
        if(len && len == (pend - pbegin))
            memcpy(vch, (unsigned char*)&pbegin[0], len);
    }

    //! Construct a public key using begin/end iterators to byte data.
    template <typename T>
    PublicKey(const T pbegin, const T pend)
    {
        set(pbegin, pend);
    }

    //! Construct a public key from a byte vector.
    explicit PublicKey(const std::vector<unsigned char> &_vch)
    {
        set(_vch.begin(), _vch.end());
    }

    // Simple read-only vector-like interface to the public key
    unsigned int size() const 
    { 
        for(int i=0; i < kPublicKeySize; i++)
        {
            if(vch[i]!=0) return kPublicKeySize;
        }
        return 0;
    }

    const unsigned char* begin() const { return vch; }
    const unsigned char* end() const { return vch + size(); }
    const unsigned char& operator[](unsigned int position) const { return vch[position]; }

    //Comparator implementation

    friend bool operator==(const PublicKey &a, const PublicKey &b)
    {
        return memcmp(a.vch, b.vch, a.size())==0;
    }

    friend bool operator!=(const PublicKey &a, const PublicKey &b)
    {
        return !(a==b);
    }

    friend bool operator<(const PublicKey &a, const PublicKey &b)
    {
        return memcmp(a.vch, b.vch, a.size()) < 0;
    }

    // Implement serialization, as if this is a byte vector
    template <typename Stream>
    void Serialize(Stream& s) const
    {
        unsigned int len = size();
        ::WriteCompactSize(s, len);
        s.write((char*) vch, len);
    }

    template <typename Stream>
    void Unserialize(Stream& s)
    {
        unsigned int len = ::ReadCompactSize(s);
        if(len <= kPublicKeySize){
            s.read((char*)vch, len);
        }else{
            char dummy;
            while(len--) s.read(&dummy, 1);
            bzero(vch, kPublicKeySize);
        }
    }

    KeyID getId() const
    {
        return KeyID(Hash160(vch, vch + size()));
    }

    uint256 getHash() const
    {
        return Hash(vch, vch + size());
    }

    bool isValid() const 
    {
        return size() > 0;
    }

    bool isFullyValid() const;

    /**
     * Verify a DER signature (~72 bytes).
     * If this public key is not fully valid, the return value will be false.
     */
    bool verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;

    /**
     * Check whether a signature is normalized (lower-S).
     */
    static bool checkLowS(const std::vector<unsigned char>& vchSig);


};


class ECCVerifyHandle
{
    static int refcount;

public:
    ECCVerifyHandle();
    ~ECCVerifyHandle();
};


#endif // !PUBLIC_KEY_HPP
